#include "drivers/7segments.h"
#include "drivers/clock.h"
#include "drivers/UART.h"

#define QUEUE_SIZE 8

#include "lib/fifo.h"



int processReceivedData(char buffer[]);
//The variable that represents the interval.
int Interval = 100;
//The variable that represents the number.
int ClockNumber = 0;

Queue ResponseQueue;

int main()
{
	ResponseQueue.Tail = 0;
	ResponseQueue.Head = 0;
	startUpUART();
	int previousTime = 0;
	//Main Loop
	int running = 1;
	writeNumberToSegments(0);
	char buffer[4];
	int charsReceived = 0;
	while(running)
	{
		//Check the clock
		int newTime = readTimeFromClock();
		if((newTime - previousTime) >= Interval)
		{
			previousTime = newTime;
			writeNumberToSegments(++ClockNumber);
			if(ClockNumber >= 0xff)
			{
				ClockNumber = 0;
			}
		}

		if(UARTreceivedData())
		{
			buffer[charsReceived++] = (char)UARTreceiveByte();
			if(charsReceived == 4)
			{
				charsReceived = 0;
				processReceivedData(buffer);
			}
		}

		if(!IsQueueEmpty(&ResponseQueue) && UARTreadyToSendData())
		{
			UARTsendByte((unsigned char)Dequeue(&ResponseQueue));
		}
	}
	return 0;
}

char convertDecToHexDigit(int dec)
{
	if(dec < 0 || dec >15)
		return 0;
	else if(dec > 0 && dec < 10)
		return '0' + dec;
	else
	{
		return 'A' + (dec - 10);
	}
}
int parseHexDigit(char digit)
{
	if(digit >= '0' && digit <= '9')
		return digit - '0';
	switch(digit)
	{
		case 'a':
		case 'A':
			return 10;
		case 'b':
		case 'B':
			return 11;
		case 'c':
		case 'C':
			return 12;
		case 'd':
		case 'D':
			return 13;
		case 'e':
		case 'E':
			return 14;
		case 'f':
		case 'F':
			return 15;
		default:
			return -1;
	}
}
//2 space buffer!
void convertDecToHex(int dec,char buffer[])
{
	int lsb = dec % 16;
	int msb = dec / 16;
	buffer[0] = convertDecToHexDigit(msb);
	buffer[1] = convertDecToHexDigit(lsb);
}

void EX1PError(char request[])
{
	Enqueue(&ResponseQueue,(unsigned char)'Z');
}
//Request Buffer of 4
void receiveEX1PRequest(char requestBuffer[],int buflen)
{
	int i;
	for(i = 0; i < 4; ++i)
	{
		if(UARTreceivedData())
		{
			requestBuffer[i] = (char)UARTreceiveByte();
		}
		else
		{
			requestBuffer[i] = '0';
		}
	}
}
void readEX1PIntervalRequest(char request[])
{
	if(request[2] != '0' || request[3] != '0')
		EX1PError(request);
	else
	{

		Enqueue(&ResponseQueue,(unsigned char)'R');
		Enqueue(&ResponseQueue,(unsigned char)'T');
		char hexBuffer[2];
		convertDecToHex(Interval,hexBuffer);
		Enqueue(&ResponseQueue,(unsigned char)hexBuffer[0]);
		Enqueue(&ResponseQueue,(unsigned char)hexBuffer[1]);
	}
}
void readEX1PClockRequest(char request[])
{
	if(request[2] != '0' || request[3] != '0')
		EX1PError(request);
	else
	{
	    Enqueue(&ResponseQueue,(unsigned char)'R');
		Enqueue(&ResponseQueue,(unsigned char)'C');
		char hexBuffer[2];
		convertDecToHex(ClockNumber,hexBuffer);
		Enqueue(&ResponseQueue,(unsigned char)hexBuffer[0]);
		Enqueue(&ResponseQueue,(unsigned char)hexBuffer[1]);
	}
}
void readEX1PRequest(char request[])
{
	switch(request[1])
	{
	case 't':
	case 'T':
		readEX1PIntervalRequest(request);
		break;
	case 'c':
	case 'C':
		readEX1PClockRequest(request);
		break;
	default:
		EX1PError(request);
		break;
	}
}
void writeEX1PIntervalRequest(char request[])
{
	int msd = parseHexDigit(request[2]);
	int lsd = parseHexDigit(request[3]);
	if(msd < 0 || lsd < 0)
		EX1PError(request);
	else
	{
		Interval = (msd * 16) + lsd;
		Enqueue(&ResponseQueue,(unsigned char)'W');
		Enqueue(&ResponseQueue,(unsigned char)'T');
		Enqueue(&ResponseQueue,(unsigned char)'0');
		Enqueue(&ResponseQueue,(unsigned char)'0');
	}
}
void writeEX1PClockRequest(char request[])
{
	int msd = parseHexDigit(request[2]);
	int lsd = parseHexDigit(request[3]);
	if(msd < 0 || lsd < 0)
		EX1PError(request);
	else
	{
		ClockNumber = (msd * 16) + lsd;
		Enqueue(&ResponseQueue,(unsigned char)'W');
		Enqueue(&ResponseQueue,(unsigned char)'C');
		Enqueue(&ResponseQueue,(unsigned char)'0');
		Enqueue(&ResponseQueue,(unsigned char)'0');
	}
}
void writeEX1PRequest(char request[])
{
	switch(request[1])
	{
	case 't':
	case 'T':
		writeEX1PIntervalRequest(request);
		break;
	case 'c':
	case 'C':
		writeEX1PClockRequest(request);
		break;
	default:
		EX1PError(request);
		break;
	}
}
int processReceivedData(char requestBuffer[])
{
	switch(requestBuffer[0])
	{
	case 'r':
	case 'R':
		readEX1PRequest(requestBuffer);
		break;
	case 'w':
	case 'W':
		writeEX1PRequest(requestBuffer);
		break;
	case '!':
		return 0;
	default:
		EX1PError(requestBuffer);
	}
	return 1;
}

